﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace System.Windows.Forms {
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Drawing;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Windows.Forms;
    using System.Windows.Forms.Layout;
    using System.Runtime.InteropServices;
    using System.Collections.Specialized;
    using System.Collections.Generic;
    using System.Globalization;


    
    /// <summary>
    /// Summary of ToolStripDropDown.
    /// </summary>
    [Designer("System.Windows.Forms.Design.ToolStripDropDownDesigner, " + AssemblyRef.SystemDesign)]
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDispatch)]
    public class ToolStripDropDown : ToolStrip {

        private ToolStripItem               ownerItem           = null;
        private bool                        isAutoGenerated     = false;
        private Point                       dropDownLocation    = Point.Empty;
        private bool                        dropShadowEnabled   = true; 
        private bool                        autoClose           = true;
        private bool                        autoSize            = true;
        private int                         countDropDownItemsAssignedTo = 0; // the number of dropdown items using this as their dropdown..
        private BitVector32                 state               = new BitVector32();
        private Point                       displayLocation     = new Point(0,0);
        private bool                        saveSourceControl   = false;

        private ToolStripDropDownDirection childDropDownDirection = ToolStripDropDownDirection.Default;
        private ToolStripDropDownCloseReason closeReason = ToolStripDropDownCloseReason.AppFocusChange;

      
        private static readonly int PropOpacity                               = PropertyStore.CreateKey();
        private static readonly int PropDDRightToLeft                         = PropertyStore.CreateKey();
        private static readonly int PropSourceControl                         = PropertyStore.CreateKey();

        private static readonly object EventOpening                             = new object();
        private static readonly object EventOpened                              = new object();
        private static readonly object EventClosed                              = new object();
        private static readonly object EventClosing                             = new object();

        private static readonly object ToolStripParkingWindowKey                = new object();

        private static readonly Padding defaultPadding                          = new Padding(1, 2, 1, 2);
        private Padding scaledDefaultPadding                                    = defaultPadding;

#if DEBUG 
     	internal static TraceSwitch DropDownActivateDebug = new TraceSwitch("DropDownActivateDebug", "Debug activation code for dropDown controls");
        internal static TraceSwitch DropDownDebugBounds = new TraceSwitch("DropDownDebugBounds", "Debug GetDropDownBounds");
        static readonly BooleanSwitch AlwaysRestrictWindows = new BooleanSwitch("AlwaysRestrictWindows", "Always make Form classes behave as though they are restricted");
#else
        internal static TraceSwitch DropDownActivateDebug;
        internal static TraceSwitch DropDownDebugBounds;
#endif
     
        private static readonly int stateLayered                     = BitVector32.CreateMask();
        private static readonly int stateAllowTransparency           = BitVector32.CreateMask(stateLayered);
        private static readonly int stateNotWorkingAreaConstrained   = BitVector32.CreateMask(stateAllowTransparency);
        private static readonly int stateInSetVisibleCore            = BitVector32.CreateMask(stateNotWorkingAreaConstrained);

        public ToolStripDropDown()
        {
            if (DpiHelper.IsScalingRequirementMet)
            {
                scaledDefaultPadding = DpiHelper.LogicalToDeviceUnits(defaultPadding);
            }

            SuspendLayout();
            Initialize();
            ResumeLayout(false);
        }

        internal ToolStripDropDown(ToolStripItem ownerItem): this()
        {
            this.ownerItem = ownerItem;
        }

        internal ToolStripDropDown(ToolStripItem ownerItem, bool isAutoGenerated) : this(ownerItem) {
            this.isAutoGenerated = isAutoGenerated;
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new bool AllowItemReorder {
            get {
                return base.AllowItemReorder;
            }
            set {
                base.AllowItemReorder = value;
            }
        }
        
        /// <summary>
        ///    <para> 
        ///       Gets or sets
        ///       a value indicating whether the opacity of the form can be
        ///       adjusted.</para>
        /// </summary>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(nameof(SR.ControlAllowTransparencyDescr))
        ]
        public bool AllowTransparency {
            get {
                return state[stateAllowTransparency];
            }
            set {
                if (value != (state[stateAllowTransparency]) && 
                    OSFeature.Feature.IsPresent(OSFeature.LayeredWindows)) {
                    state[stateAllowTransparency] = value;

                    state[stateLayered] = state[stateAllowTransparency];

                    UpdateStyles();

                    if (!value) {
                        if (Properties.ContainsObject(PropOpacity)) {
                            Properties.SetObject(PropOpacity, (object)1.0f);
                        }
                       UpdateLayered();
                    }
                }
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override AnchorStyles Anchor {
            get {
                return base.Anchor;
            }
            set {
                base.Anchor = value;
            }
        }
        
        [DefaultValue(true)]
        public override bool AutoSize {
            get {
                return autoSize; 
            }
            set {
                if (autoSize != value) {
                    autoSize = value;
                    // we shadow CommonProperties 
                    LayoutTransaction.DoLayout(this,this,PropertyNames.AutoSize);
                    OnAutoSizeChanged(EventArgs.Empty);
                }
            }
        }
 
        /// <summary>
        /// specifies whether the dropdown should automatically close when the dropdown has lost
        /// activation.  If you want a dropdown that always stays open, specify AutoClose = false;
        /// </summary>
        [
        DefaultValue(true),
        SRCategory(nameof(SR.CatBehavior)),
        SRDescription(nameof(SR.ToolStripDropDownAutoCloseDescr))
        ]
        public bool AutoClose {
            get {
                return autoClose;
            }
            set {
                // 
                if (autoClose != value) {
                    autoClose = value;
                    ApplyTopMost(/*topMost=*/!autoClose);
                }
            }
        }


        [Browsable(false)]
        public new event EventHandler BackgroundImageChanged {
            add => base.BackgroundImageChanged += value;
            remove => base.BackgroundImageChanged -= value;
        }

        [Browsable(false)]
        public new event EventHandler BackgroundImageLayoutChanged {
            add => base.BackgroundImageLayoutChanged += value;
            remove => base.BackgroundImageLayoutChanged -= value;
        }

        [Browsable(false)]
        public new event EventHandler BindingContextChanged {
            add => base.BindingContextChanged += value;
            remove => base.BindingContextChanged -= value;
        }

        [DefaultValue(false), 
         Browsable(false), 
         EditorBrowsable(EditorBrowsableState.Never)]
        public new bool CanOverflow { 
            get { 
                return base.CanOverflow;             
            }
            set { 
                base.CanOverflow = value;
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        new public event UICuesEventHandler ChangeUICues {
            add => base.ChangeUICues += value; 
            remove => base.ChangeUICues -= value; }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new ContextMenu ContextMenu {
            get { return base.ContextMenu; }
            set { base.ContextMenu = value; }
        }


        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ContextMenuChanged {
            add => base.ContextMenuChanged += value; 
            remove => base.ContextMenuChanged -= value; }


        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new ContextMenuStrip ContextMenuStrip {
            get { return base.ContextMenuStrip; }
            set { base.ContextMenuStrip = value; }
        }


        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        public new event EventHandler ContextMenuStripChanged {
            add => base.ContextMenuStripChanged += value; 
            remove => base.ContextMenuStripChanged -= value; }
        
        /// <summary>
        /// <para>
        /// This is called when creating a window. Inheriting classes can overide
        /// this to add extra functionality, but should not forget to first call
        /// base.CreateParams() to make sure the control continues to work
        /// correctly.
        /// </para>
        /// </summary>
        protected override CreateParams CreateParams {
            get {
                CreateParams cp = base.CreateParams;

                // If we're using themes then go ahead 
                if (DropShadowEnabled) {
                    cp.ClassStyle |= NativeMethods.CS_DROPSHADOW;
                }
                // we're a borderless menuless control with no min/max boxes
                // we dont want to show in the taskbar either
                
                //HOWTO: Prevent a Window from Appearing on the Taskbar
                //Give the window the WS_EX_TOOLWINDOW extended style, and remove the WS_EX_APPWINDOW style. As a side effect, the window will have a smaller caption than a normal window. 
                //Give the window the WS_POPUP style and make it owned by a hidden window. (Form)

                cp.Style &= ~(NativeMethods.WS_CAPTION | NativeMethods.WS_CLIPSIBLINGS);         /* no caption, no siblings */
                cp.ExStyle &= ~(NativeMethods.WS_EX_APPWINDOW);  /* show in taskbar = false */
                // | NativeMethods.WS_EX_TOOLWINDOW
                cp.Style |= (TopLevel) ? NativeMethods.WS_POPUP : NativeMethods.WS_CHILD;
                cp.ExStyle |= (NativeMethods.WS_EX_CONTROLPARENT);  /* show in taskbar = false */

                bool topLevel = TopLevel;
                
                // opacity 
                if (topLevel && (state[stateLayered])) {
                    cp.ExStyle |= NativeMethods.WS_EX_LAYERED;
                }
                else if (topLevel) {
                    //From MSDN: Menus, dialog boxes, and combo list boxes have the CS_SAVEBITS style. When you use this style for a window, 
                    //Windows saves a bitmap copy of the screen image that the window obscures. First, Windows asks the display driver to save the bits.
                    //If the display driver has enough memory, it saves the bits for Windows. If the display driver does not have enough memory, Window 
                    //saves the bits itself as a bitmap in global memory and also uses some of User's local heap for housekeeping structures for each window. 
                    //When the application removes the window, Windows can restore the screen image quickly by using the stored bits.
                    cp.ClassStyle |= NativeMethods.CS_SAVEBITS;
                }
                else if (!topLevel) {
                    cp.Style |= NativeMethods.WS_CLIPSIBLINGS;
                }
                
                // We're turning off CLIPSIBLINGS because in the designer the elements of the form beneath
                // are actually sibling controls.  We want to paint right over them as if we were a toplevel window.

                return cp;
            }
        }

        protected override Padding DefaultPadding {
            get { return scaledDefaultPadding; }
        }


        /// <summary> We want this to default to true... This way tooltips on overflows and custom dropdowns will show. 
        /// Since menu items don't show tooltips by default we can savely leave it on </summary>
        protected override bool DefaultShowItemToolTips {
           get {
               return true;
           }
        }

        protected override DockStyle DefaultDock {
           get {
               return DockStyle.None;
           }
        }

        public override ToolStripDropDownDirection DefaultDropDownDirection {
           get {
               if (childDropDownDirection == ToolStripDropDownDirection.Default) {
                   return (RightToLeft ==  RightToLeft.Yes)? ToolStripDropDownDirection.Left : ToolStripDropDownDirection.Right;
               }
               return childDropDownDirection;
           }
           set {
               childDropDownDirection = value;
               base.DefaultDropDownDirection = value;
           }
       }
       
        [
        DefaultValue(DockStyle.None),
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Always)]
        public override DockStyle Dock {
            get {
               return base.Dock;
            }
            set{
                base.Dock = value;
            }
        }

        /// changed the browsable attribute
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        public new event EventHandler DockChanged {
            add => base.DockChanged += value;
            remove => base.DockChanged -= value;
        }
        
        /// <summary>
        ///     Returns an owner window that can be used to
        ///     own a drop down.
        /// </summary>
        internal override NativeWindow DropDownOwnerWindow {
            get {
                // Re-use the drop down owner from our parenting
                // tool strip if we can.
                if (ownerItem != null && ownerItem.Owner != null) {
                    return ownerItem.Owner.DropDownOwnerWindow;
                }

                return base.DropDownOwnerWindow;
            }
        }

        public bool DropShadowEnabled {
            get {
                // DropShadows are only supported on TopMost windows 
                // due to the flakeyness of the way it's implemented in the OS. (Non toplevel 
                // windows can have parts of the shadow disappear because another window can get
                // sandwiched between the SysShadow window and the dropdown.)
                return dropShadowEnabled && TopMost && DisplayInformation.IsDropShadowEnabled;
            }
            set {
                if (dropShadowEnabled != value) {
                    dropShadowEnabled = value;
                    if (IsHandleCreated && !DesignMode) {
                        RecreateHandle();
                    }
                }
            }
        }

        [SRCategory(nameof(SR.CatAction)), SRDescription(nameof(SR.ToolStripDropDownClosedDecr))]
        public event ToolStripDropDownClosedEventHandler Closed {
            add => Events.AddHandler(EventClosed, value); 
            remove => Events.RemoveHandler(EventClosed, value);
        }

        [SRCategory(nameof(SR.CatAction)), SRDescription(nameof(SR.ToolStripDropDownClosingDecr))]
        public event ToolStripDropDownClosingEventHandler Closing {
            add => Events.AddHandler(EventClosing, value); 
            remove => Events.RemoveHandler(EventClosing, value);
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        new public event EventHandler Enter {
            add => base.Enter += value; 
            remove => base.Enter -= value; }

        public override Font Font {
            get {
                if (this.IsFontSet()) {
                    return base.Font;
                }
                // if the FONT isnt set, then return our owner item's font.
                if (IsAutoGenerated && OwnerItem != null) {
                    return OwnerItem.Font;
                }
                
                return base.Font;
            }
            set {
                base.Font = value;
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        new public event EventHandler FontChanged {
            add => base.FontChanged += value; 
            remove => base.FontChanged -= value; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler ForeColorChanged {
            add => base.ForeColorChanged += value; 
     remove => base.ForeColorChanged -= value; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event GiveFeedbackEventHandler GiveFeedback {
            add => base.GiveFeedback += value; 
            remove => base.GiveFeedback -= value; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new ToolStripGripDisplayStyle GripDisplayStyle {
            get {
                return base.GripDisplayStyle;
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new Rectangle GripRectangle {
            get {
                return base.GripRectangle;
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Padding GripMargin{
            get {
                return base.GripMargin;
            }
            set {
                base.GripMargin = value;
            }
        }
        
        [DefaultValue(ToolStripGripStyle.Hidden), 
         Browsable(false), 
         EditorBrowsable(EditorBrowsableState.Never)]
        public new ToolStripGripStyle GripStyle {
           get { 
               return base.GripStyle;      
           }
           set { 
              base.GripStyle = value;
           }        
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        [SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] //Everett
        new public event HelpEventHandler HelpRequested {
            add => base.HelpRequested += value; 
            remove => base.HelpRequested -= value; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        public new event EventHandler ImeModeChanged {
            add => base.ImeModeChanged += value; 
            remove => base.ImeModeChanged -= value; }

        /// <summary>
        /// determines whether this dropdown was autogenerated.
        /// </summary>
        [Browsable(false)]
        public bool IsAutoGenerated {
            get {
                return isAutoGenerated;
            }
        }

        internal bool IsAssignedToDropDownItem {
            get {
                return IsAutoGenerated || (countDropDownItemsAssignedTo > 0);
            }
        }

        internal override Size ImageScalingSizeInternal {
            get {
                if (IsAutoGenerated && OwnerToolStrip != null) {
                    return OwnerToolStrip.ImageScalingSizeInternal;
                }
                return base.ImageScalingSizeInternal;
            }
            set {
                 base.ImageScalingSizeInternal = value; 
            }
        }

        internal override bool KeyboardActive {
            get { 
                // ripple up the chain until we get the topmost toolstrip (usually the main menu strip is the one we care about)
                ToolStrip ownerToolStrip = OwnerToolStrip;               
                if (ownerToolStrip != null) {
                    return ownerToolStrip.KeyboardActive;
                }
                return base.KeyboardActive;
            }
            set {
                base.KeyboardActive = value;

                // ripple up the chain until we get the topmost toolstrip (usually the main menu strip is the one we care about)
                ToolStrip ownerToolStrip = OwnerToolStrip;                
                if (ownerToolStrip != null) {
                    ownerToolStrip.KeyboardActive = value;
                }


            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        new public event KeyEventHandler KeyDown {
            add => base.KeyDown += value; 
            remove => base.KeyDown -= value; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        new public event KeyPressEventHandler KeyPress {
            add => base.KeyPress += value; 
            remove => base.KeyPress -= value; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        new public event KeyEventHandler KeyUp {
            add => base.KeyUp += value; 
            remove => base.KeyUp -= value; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        public new event EventHandler Leave {
            add => base.Leave += value; 
            remove => base.Leave -= value; }

        /// <summary>
        ///     Override Location to make it hidden from the user in the designer
        /// </summary>
        [
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        Browsable(false)    
        ]
        public new Point Location {
            get {
                return base.Location;
            }
            set {
                base.Location = value;
            }
        }

        [SRCategory(nameof(SR.CatAction)), SRDescription(nameof(SR.ToolStripDropDownOpeningDescr))]
        public event CancelEventHandler Opening {
            add => Events.AddHandler(EventOpening, value);
            remove => Events.RemoveHandler(EventOpening, value);
        }

      
        /// <summary>
        /// <para>Occurs when the control is clicked.</para>
        /// </summary>
        [SRCategory(nameof(SR.CatAction)), SRDescription(nameof(SR.ToolStripDropDownOpenedDescr))]
        public event EventHandler Opened {
            add => Events.AddHandler(EventOpened, value); 
            remove => Events.RemoveHandler(EventOpened, value);
        }

        protected internal override Size MaxItemSize {
            get {
              return Screen.GetWorkingArea(this.Bounds).Size - this.Padding.Size;
            }
        }

        /// <summary>
        /// Determines the opacity of the form. This can only be set on top level controls.
        /// Opacity requires Windows 2000 or later, and is ignored on earlier operating systems.
        /// </summary>
        [SRCategory(nameof(SR.CatWindowStyle))]
        [TypeConverterAttribute(typeof(OpacityConverter))]
        [SRDescription(nameof(SR.FormOpacityDescr))]
        [DefaultValue(1.0)]
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public double Opacity
        {
            get
            {
                object opacity = Properties.GetObject(PropOpacity);
                if (opacity != null)
                {
                    return Convert.ToDouble(opacity, CultureInfo.InvariantCulture);
                }
                
                return 1.0f;
            }
            set
            {
                if (value > 1.0)
                {
                    value = 1.0f;
                }
                else if (value < 0.0)
                {
                    value = 0.0f;
                }

                Properties.SetObject(PropOpacity, value);

                bool oldLayered = (state[stateLayered]);
                if (OpacityAsByte < 255 && OSFeature.Feature.IsPresent(OSFeature.LayeredWindows))
                {
                    AllowTransparency = true;
                    state[stateLayered] = true;
                }
                else
                {
                    state[stateLayered] = false;
                }

                if (oldLayered != (state[stateLayered]))
                {
                    UpdateStyles();
                }
    
                UpdateLayered();
            }
        }
        
        private byte OpacityAsByte {
            get {
                return (byte)(Opacity * 255.0f);
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new ToolStripOverflowButton OverflowButton {
            get {
                return base.OverflowButton;
            }
        }

        
        /// <summary>
        /// Summary of OwnerItem.
        /// </summary>
        [DefaultValue(null), Browsable(false)]
        public ToolStripItem OwnerItem {
            get { return ownerItem; }
            set { 
                  if (ownerItem != value) {
                    Font originalFont = this.Font;
                    RightToLeft startRightToLeft = this.RightToLeft;
                    ownerItem = value;
                    // RESET ambient properties
                    if (!originalFont.Equals(Font)) {
                        OnOwnerItemFontChanged(EventArgs.Empty);
                    }
                    if (ownerItem != null && RightToLeftInherited && startRightToLeft != this.RightToLeft) {
                        using (new LayoutTransaction(this,this,PropertyNames.RightToLeft)) {
                            OnRightToLeftChanged(EventArgs.Empty);
                        }
                    }
                  }
            }
        }

        internal ToolStripDropDownItem OwnerDropDownItem {
            get { return OwnerItem as ToolStripDropDownItem; }
        }

        internal ToolStrip OwnerToolStrip {
            get {
                if (ownerItem != null) {
                    ToolStrip owner = ownerItem.ParentInternal;
                    if (owner != null) {
                        return owner;
                    }

                    // might not actually be placed on the overflow, just check for sure.
                    if (ownerItem.Placement == ToolStripItemPlacement.Overflow && ownerItem.Owner != null) {
                        return ownerItem.Owner.OverflowButton.DropDown;
                    }
                    if (owner == null) {
                        return ownerItem.Owner;
                    }
                }
                return null;
            }
        }

        /// <summary>
        ///     Hide the Region Property
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        new public Region Region {
            get {
                return base.Region;
            }
            set {
                base.Region = value;
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        new public event EventHandler RegionChanged {
            add => base.RegionChanged += value; 
            remove => base.RegionChanged -= value; }

       
        internal virtual bool RequiresScrollButtons {
            get {
                return false; 
            }
            set {
                Debug.Fail("You can't set this except on ToolStripDropDownMenu");
            }
        }


       [
       SRCategory(nameof(SR.CatAppearance)),
       Localizable(true),
       AmbientValue(RightToLeft.Inherit),
       SRDescription(nameof(SR.ControlRightToLeftDescr))
       ]
       public override RightToLeft RightToLeft {
           get {
                // our inheritance is from our owner item.
                if (RightToLeftInherited) {
                    if (SourceControlInternal != null) {
                        return SourceControlInternal.RightToLeft;
                    }
                    if (OwnerItem != null) {
                        return OwnerItem.RightToLeft;
                    }
                }
                return base.RightToLeft;
           }
           set {
               base.RightToLeft = value;
           }
       }

       private bool RightToLeftInherited {
            get {
                // fish out of control's property store whether or not RTL was set, if it's set to inherit.
                return !ShouldSerializeRightToLeft();
            }
       }
    
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event ScrollEventHandler Scroll {
            add => base.Scroll += value; 
            remove => base.Scroll -= value; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new bool Stretch {
            get {
                return base.Stretch;
            }
            set {
                base.Stretch = value;
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Always)]
        new public event EventHandler StyleChanged {
            add => base.StyleChanged += value; 
            remove => base.StyleChanged -= value; }


       internal Control SourceControlInternal {
            get {
                return Properties.GetObject(PropSourceControl) as Control;
            }
            set{
                Properties.SetObject(PropSourceControl, value);
            }
       }
       
       internal override int ShowParams {
           get {
               return NativeMethods.SW_SHOWNOACTIVATE;
           }
       }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler TabStopChanged {
            add => base.TabStopChanged += value; 
            remove => base.TabStopChanged -= value; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler TextChanged {
            add => base.TextChanged += value; 
            remove => base.TextChanged -= value; }

       [
       Browsable(false),
       DefaultValue(ToolStripTextDirection.Horizontal),
       SRDescription(nameof(SR.ToolStripTextDirectionDescr)),
       SRCategory(nameof(SR.CatAppearance))
       ]
       public override ToolStripTextDirection TextDirection {
           get {
               return base.TextDirection;
           }
           set {
               base.TextDirection = value;
           }
       }
           

       //Consistency: match casing of Form.TopMost, which shipped in Everett, even though it's wrong
       [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]
       protected virtual bool TopMost
       {
            get { return true; }
       }


      [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
       public bool TopLevel {
            get {
                return GetTopLevel();
            }
            set {
                // 
                if (value != GetTopLevel()) {
                    SetTopLevelInternal(value);
                    SetTopLevelStyle(value);
                }
            }
        }


// public Color TransparencyKey {  
//    This property intentionally not available for ToolStripDropDown
//    it's not robust enough for our needs
// }

          /// Override base TabIndex property in order to avoid serialization
          /// (since a dropdown shouldn't participate in the taborder...)
          [
          EditorBrowsable(EditorBrowsableState.Never),
          DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
          Browsable(false)    
          ]
          public new int TabIndex {
              get {
                  return base.TabIndex;
              }
              set {
                  base.TabIndex = value;
              }
          }

          [
          Browsable(false), 
          EditorBrowsable(EditorBrowsableState.Never), 
          SRCategory(nameof(SR.CatPropertyChanged)), 
          SRDescription(nameof(SR.ControlOnTabIndexChangedDescr))
          ]
          public new event EventHandler TabIndexChanged {
              add => base.TabIndexChanged += value;
              remove => base.TabIndexChanged -= value;
          }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler Validated {
            add => base.Validated += value; 
            remove => base.Validated -= value; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event CancelEventHandler Validating {
            add => base.Validating += value; 
            remove => base.Validating -= value; }

        /// Override base Visible property in order to control serialization by setting default value
        [
                SRCategory(nameof(SR.CatBehavior)),
                Localizable(true),
                SRDescription(nameof(SR.ControlVisibleDescr)),
                DefaultValue(false),
                Browsable(false),
                DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public new bool Visible {
            get {
                return base.Visible;
            }
            set {
                base.Visible = value;
            }
        }

        // internally we use not so we dont have to initialize it.
        internal bool WorkingAreaConstrained
        {
            get => true;
            set 
            {
                bool notConstrained = !value;
                state[stateNotWorkingAreaConstrained] = !value;
            }
        }

        internal void AssignToDropDownItem() {
            countDropDownItemsAssignedTo++;
        }

        internal void AdjustSize() {
            Size size = GetSuggestedSize();
            if (size != this.Size) {
                this.Size = size;
            }
        }

        private void ApplyTopMost(bool topMost) {
            if (TopMost) {
                HandleRef topMostFlag = (topMost) ? NativeMethods.HWND_TOPMOST : NativeMethods.HWND_NOTOPMOST;
                SafeNativeMethods.SetWindowPos(new HandleRef(this, Handle), topMostFlag, 0, 0, 0, 0,
                                             NativeMethods.SWP_NOMOVE | NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOACTIVATE);
            }
        }

        protected override void Dispose(bool disposing) {
            if (disposing) {
                SourceControlInternal = null;
            }
            base.Dispose(disposing);
        }


        private void CancelAutoExpand() {
            ToolStrip toplevelOwnerToolStrip = GetToplevelOwnerToolStrip();
            if (toplevelOwnerToolStrip != null) {
                toplevelOwnerToolStrip.MenuAutoExpand = false;
            }
        }

        internal override bool CanProcessMnemonic()
        {
            // Dont let mnemonics act as keyboard input in IE in the internet.
            if (Application.MessageLoop)
            {
                return false;
            }

            return base.CanProcessMnemonic();
        }

        protected override AccessibleObject CreateAccessibilityInstance() {
            return new ToolStripDropDownAccessibleObject(this);
        }

        protected override LayoutSettings CreateLayoutSettings(ToolStripLayoutStyle style) {
            LayoutSettings layoutSettings = base.CreateLayoutSettings(style);
            
            if (style == ToolStripLayoutStyle.Flow) {
                FlowLayoutSettings flowLayoutSettings = layoutSettings as FlowLayoutSettings;
                flowLayoutSettings.FlowDirection = FlowDirection.TopDown;
                flowLayoutSettings.WrapContents = false;
                return flowLayoutSettings;
            }
            return layoutSettings;
        }

        protected override void CreateHandle() {
            base.CreateHandle();
            
            if (TopLevel) {
                ReparentToDropDownOwnerWindow();

                if (!AutoClose || !WorkingAreaConstrained) {
                    ApplyTopMost(true);
                }

            }
            if (DesignMode) {
                SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, false);
            }

        }

        public void Close() {
            SetCloseReason(ToolStripDropDownCloseReason.CloseCalled);
            this.Visible = false;
            // we were the last one in the chain, roll out of menu mode.
            if (ToolStripManager.ModalMenuFilter.GetActiveToolStrip() == null) {
                ToolStripManager.ModalMenuFilter.ExitMenuMode();
            }
        }

        private void ResetCloseReason() {
            closeReason =  ToolStripDropDownCloseReason.AppFocusChange;
        }
        internal void SetCloseReason(ToolStripDropDownCloseReason reason) {
            closeReason =  reason;
        }
        
        
        public void Close(ToolStripDropDownCloseReason reason) {
            SetCloseReason(reason);
            this.Visible = false;
        }

        /// <summary>
        /// Summary of GetBaseDropDownBounds.
        /// </summary>
        // called by ToolStripDropDownMenu,
        internal Rectangle GetDropDownBounds(Rectangle suggestedBounds) {

            Rectangle dropDownBounds;
            if (TopLevel) {
                Point screenPoint = Point.Empty;

                if ((ownerItem != null) && (ownerItem is ToolStripDropDownItem)) {
                    screenPoint = ((ToolStripDropDownItem)ownerItem).DropDownLocation;
                }
                else {
                    screenPoint = suggestedBounds.Location;
                }

                Rectangle suggestedScreenBounds =  new Rectangle(screenPoint, suggestedBounds.Size);
                if (WorkingAreaConstrained) {
                    dropDownBounds =  WindowsFormsUtils.ConstrainToScreenWorkingAreaBounds(suggestedScreenBounds);
                }
                else {
                    dropDownBounds =  WindowsFormsUtils.ConstrainToScreenBounds(suggestedScreenBounds);
                }
            }
            else {
                Point parentClientPoint = Point.Empty;
                if ((ownerItem != null) && (ownerItem is ToolStripDropDownItem) && (ParentInternal != null)) {
                    parentClientPoint = ParentInternal.PointToClient(((ToolStripDropDownItem)ownerItem).DropDownLocation);
                }
                else {
                    parentClientPoint = suggestedBounds.Location;
                }
                dropDownBounds = new Rectangle(parentClientPoint, suggestedBounds.Size);

            }
            Debug.WriteLineIf(DropDownDebugBounds.TraceVerbose, "DropDownBounds for " + suggestedBounds + "is" +dropDownBounds);
               
            return dropDownBounds; 
            
        }
        
        internal Rectangle CalculateDropDownLocation(Point start, ToolStripDropDownDirection dropDownDirection) {
            Point offset = Point.Empty;
            if (!IsHandleCreated) {
                // PERF:
                // if the handle isnt created yet, then we likely havent performed layout
                // yet.  force a layout here so that we get the correct size.
                LayoutTransaction.DoLayout(this, this, PropertyNames.PreferredSize);
            }
            Rectangle dropDownBounds = new Rectangle(Point.Empty, GetSuggestedSize());
            // calculate the offset from the upper left hand corner of the item.
            switch (dropDownDirection) {
                case ToolStripDropDownDirection.AboveLeft:
                    offset.X = - dropDownBounds.Width;
                    offset.Y = - dropDownBounds.Height;
                    break;
                case ToolStripDropDownDirection.AboveRight:                        
                    offset.Y = - dropDownBounds.Height;
                    break;
                case ToolStripDropDownDirection.BelowRight:
                case ToolStripDropDownDirection.Right:
                    break;
                case ToolStripDropDownDirection.BelowLeft:
                case ToolStripDropDownDirection.Left:
                    offset.X = - dropDownBounds.Width;
                    break;
            }
            dropDownBounds.Location =  new Point(start.X + offset.X, start.Y + offset.Y);
            if (WorkingAreaConstrained) {
                dropDownBounds =  WindowsFormsUtils.ConstrainToScreenWorkingAreaBounds(dropDownBounds);
            }
            return dropDownBounds;
    
        }

        internal Size GetSuggestedSize() {
            if (AutoSize) {
                return GetPreferredSize(Size.Empty);
            }
            return this.Size;
        }
      
        /// <summary>
        /// Returns the ToolStrip from which all the dropdowns started from.  This can be null. 
        /// </summary>
        internal override ToolStrip GetToplevelOwnerToolStrip() {
            ToolStripDropDown topmost = GetFirstDropDown();
            return (topmost.OwnerItem == null) ? null : topmost.OwnerToolStrip;
        }

        internal ToolStripItem GetToplevelOwnerItem() {
             ToolStripDropDown topmost = GetFirstDropDown();
             return topmost.OwnerItem;
        }

        internal override void HandleItemClicked(ToolStripItem dismissingItem) {
            // Only clear the SourceControl if this is the last click.
            if (!LocalAppContextSwitches.UseLegacyContextMenuStripSourceControlValue &&
                this.ActiveDropDowns.Count == 0) {
                // post processing after the click has happened.
                SourceControlInternal = null;
            }
            base.HandleItemClicked(dismissingItem);
        }
        /// <summary>
        /// Set some common properties
        /// </summary>	
        internal virtual void Initialize() {
            SetState(STATE_VISIBLE, false);
            SetTopLevelInternal(true);
            
            // Marking this as a modal form prevents it from being activated
            // by the IMsoComponentManager, which will break keyboard routing in VS.
            //
            SetState(STATE_MODAL, true);
            
            SetStyle(ControlStyles.ResizeRedraw, true);
            this.UpdateStyles();
            this.GripStyle      = ToolStripGripStyle.Hidden;
            this.CanOverflow    = false;
            this.LayoutStyle    = ToolStripLayoutStyle.Flow;
            this.MenuAutoExpand = true;
            this.AutoSize       = true;
        }


        /// <summary>
        /// Summary of OnLayout.
        /// </summary>
        /// <param name=e></param>
        protected virtual void OnClosed(ToolStripDropDownClosedEventArgs e){
             if (IsHandleCreated) {
                if (ownerItem == null || !ownerItem.IsInDesignMode)
                {
                    AccessibilityNotifyClients(AccessibleEvents.SystemMenuPopupEnd, -1);
                }
             }
             ToolStripDropDownClosedEventHandler handler = (ToolStripDropDownClosedEventHandler)Events[EventClosed];
             if (handler != null) handler(this, e);
        }
        
        // 


        protected virtual void OnClosing(ToolStripDropDownClosingEventArgs e) {
             ToolStripDropDownClosingEventHandler handler = (ToolStripDropDownClosingEventHandler)Events[EventClosing];
             if (handler != null) handler(this, e);
        }
        /// <summary>
        /// When our handle is being created, suspend the deactivation
        /// portion of the WndProc, as we'll never be shown.
        /// </summary>
        protected override void OnHandleCreated(EventArgs e) {
             UpdateStyles();  // get rid of WS_CAPTION style
             base.OnHandleCreated(e);
             UpdateLayered(); // update transparency
        }

        

        protected override void OnItemClicked(ToolStripItemClickedEventArgs e) {
            try {
                base.OnItemClicked(e);
            }
            finally {
                ToolStripDropDownItem dismissingItem = e.ClickedItem as ToolStripDropDownItem;
                if (AutoClose) {
                    if ((dismissingItem == null)                   // it's not a dropdownitem
                       || (dismissingItem is ToolStripSplitButton && !dismissingItem.DropDown.Visible) // clicking on the split button button dismisses
                       || !(dismissingItem.HasDropDownItems)) {    // clicking on a item w/dropdown does not dismiss window
                       Close(ToolStripDropDownCloseReason.ItemClicked);
                    }
                }
            }
        
        }
       
     
        protected override void OnLayout(LayoutEventArgs e) {
            // It's important to size the dropdown first, then layout so that 
            // the layout engine and SetDisplayedItems know how big the container is.
            AdjustSize();
            base.OnLayout(e);
          
        }

        protected virtual void OnOpening(CancelEventArgs e){
            CancelEventHandler handler = (CancelEventHandler)Events[EventOpening];
            if (handler != null) handler(this, e);
        }


        /// <summary>
        /// Summary of OnLayout.
        /// </summary>
        /// <param name=e></param>
        protected virtual void OnOpened(System.EventArgs e) {
            if (IsHandleCreated) {
                if (ownerItem == null || !ownerItem.IsInDesignMode)
                {
                    AccessibilityNotifyClients(AccessibleEvents.SystemMenuPopupStart, -1);
                }
            }

            EventHandler handler = (EventHandler)Events[EventOpened];
            if (handler != null) handler(this, e);
        }

        protected override void OnVisibleChanged(System.EventArgs e) {
            if (this.Location != this.displayLocation) {
                // If we adjusted the position from where the user wanted it,
                // see if we can put it in the right location now that they've changed
                // the items collection, and store where we actually have it.

                // Just because this is the case doesn't mean that we need to do another
                // another layout however.
                this.Location = this.displayLocation;
                this.displayLocation = this.Location;
            }
            if (AutoScroll || this.LayoutRequired) {
                // the base here forces a layout... we really only want to do this the first
                // time we pop the window... the subsequent times should be snappy.
                base.OnVisibleChanged(e);
            }
            else {
                this.SuspendLayout();
                try {
                    // scrollable control forces a layout here for scrollbar reasons only
                    // since we toggle visibility a lot this is expensive.  Let's be clever and
                    // not do it.
                    base.OnVisibleChanged(e);
                }
                finally {
                    this.ResumeLayout(false);
                }
            }
        }

        protected override void OnParentChanged(System.EventArgs e) {
            base.OnParentChanged(e);
            Rectangle bounds =  this.Bounds;
            SetBoundsCore(bounds.X, bounds.Y, bounds.Width, bounds.Height, BoundsSpecified.Location);
        }
        protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs mea) {
            base.OnMouseUp(mea);
            Debug.WriteLineIf(ToolStrip.SnapFocusDebug.TraceVerbose, "[ToolStripDropDown.OnMouseUp] mouse up outside of the toolstrip - this should dismiss the entire chain");

            // Menus should dismiss when you drag off
            if (!ClientRectangle.Contains(mea.Location)) {
                bool dismiss = true;
                if (OwnerToolStrip != null && OwnerItem != null) {
                    if (OwnerItem.Bounds.Contains(WindowsFormsUtils.TranslatePoint(mea.Location, this, OwnerToolStrip))) {
                        dismiss = false;  // dont dismiss if we clicked on our owner item
                    }
                }
                if (dismiss) {
                    DismissAll();
                    CancelAutoExpand();
                }
            }
        }

        internal void OnOwnerItemFontChanged(EventArgs e) {
            if (this.IsAutoGenerated) {
                using (new LayoutTransaction(this, OwnerItem, PropertyNames.Font)) {
                    OnFontChanged(e);
                }
            }
        }

        internal void SelectPreviousToolStrip() {
            // snap the owner item before calling hide as non-auto created dropdowns will
            // exit menu mode if there's no OwnerItem.
            ToolStripItem itemOnPreviousMenuToSelect = this.OwnerItem;
            this.Hide();

            if (itemOnPreviousMenuToSelect != null) {
                itemOnPreviousMenuToSelect.Select();

                KeyboardToolTipStateMachine.Instance.NotifyAboutGotFocus(itemOnPreviousMenuToSelect);

                if (OwnerToolStrip != null) {
                    // make sure we send keyboard handling where we've just
                    // sent selection
                    if (!OwnerToolStrip.IsDropDown) {
                        if (ToolStripManager.ModalMenuFilter.GetActiveToolStrip() != OwnerToolStrip) {
                            ToolStripManager.ModalMenuFilter.SetActiveToolStrip(OwnerToolStrip);
                        }
                        // escape should cancel auto expansion
                        OwnerToolStrip.MenuAutoExpand = false;
                        // When the control cannot be select (TabStop), we can press "Tab" to
                        // navigate inside the owner toolstip. Otherwise, press "Tab" will leave
                        // the owner toolstrip so it should exit the menu mode.
                        if (OwnerToolStrip.CanSelect) {
                            ToolStripManager.ModalMenuFilter.ExitMenuMode();
                        }
                    }
                }
            }
            else {
                Debug.WriteLineIf(ToolStrip.SnapFocusDebug.TraceVerbose, "[ToolStripDropDown.SelectPreviousToolStrip] No previous toolstrip to select - exiting menu mode.");
                ToolStripManager.ModalMenuFilter.ExitMenuMode();
            }
          
        }


        /// <summary>
        ///  this is where we handle navigation between the File,Edit,View dropdowns
        ///  if you have one of these dropdowns showing and you hit the arrow key
        ///  and it's not processed by the menu item
        ///  </summary>
        internal override bool ProcessArrowKey(Keys keyCode) {

            Debug.WriteLineIf(ToolStrip.MenuAutoExpandDebug.TraceVerbose, "[ToolStripDropDown.ProcessArrowKey] MenuTimer.Cancel called");

            ToolStripMenuItem.MenuTimer.Cancel();
            
            if (keyCode == Keys.Left || keyCode == Keys.Right) {
                
                bool rightAligned = SystemInformation.RightAlignedMenus;
                bool forward = (keyCode == Keys.Left && rightAligned) ||  (keyCode == Keys.Right && !rightAligned);
                
                if (!IsFirstDropDown && !forward) {
                    // this is the case where you've casecaded out to a second level dropdown and you hit the back arrow
                    // key.  In this case we want to just hide the current dropdown
                    this.Visible = false;
                    return true;
                }
                else {
                    bool closeOnHorizontalKey = false;
                    if (LayoutStyle == ToolStripLayoutStyle.Flow) {
                        closeOnHorizontalKey = FlowLayout.GetFlowDirection(this) == FlowDirection.TopDown && !FlowLayout.GetWrapContents(this);
                    }

                    if (closeOnHorizontalKey) {

                        ToolStrip toplevelToolStrip = GetToplevelOwnerToolStrip();
                        ToolStripItem rootItem = GetToplevelOwnerItem();

                        // This is the case where you need to open up the adjacent DropDown (File->Edit) menus because:
                        //      - this is the toplevel ToolStripDropDown and you hit left or right 
                        //      - this is a non-toplevel ToolStripDropDown and you hit an arrow key in a direction 
                        //        of the cascade AND the current item has no cascading menu associated with it.

                        bool isOnOverflow = (OwnerItem != null && OwnerItem.IsOnOverflow);
                        if (forward || !isOnOverflow) {
                            SetCloseReason(ToolStripDropDownCloseReason.Keyboard);
                            DismissAll();
                        }
                        else if (isOnOverflow) {
                            // Going backwards should roll us up and our children but not the overflow.
                            Visible = false;
                        }

                        if (toplevelToolStrip != null && rootItem != null) {
                            if (ToolStripManager.ModalMenuFilter.GetActiveToolStrip() != toplevelToolStrip) {
                                ToolStripManager.ModalMenuFilter.SetActiveToolStrip(toplevelToolStrip);
                            }
                            toplevelToolStrip.SelectNextToolStripItem(rootItem,forward);
                        }
                        return true;
                    }
                }
            }
            // get base behavior like up/down navigation.
            return base.ProcessArrowKey(keyCode);
        }


        protected override bool ProcessDialogKey(Keys keyData) {
            if (this.OwnerItem != null && this.OwnerItem.IsInDesignMode) {
                return false;
            }
            
            if (AutoClose && Visible)  {
                if (ToolStripManager.IsMenuKey(keyData)) {
                    SetCloseReason(ToolStripDropDownCloseReason.Keyboard);
                    DismissAll();
                    ToolStrip toplevel = GetToplevelOwnerToolStrip();
                    if (toplevel != null) {
                      Debug.WriteLineIf(ToolStrip.SnapFocusDebug.TraceVerbose, "[ToolStripDropDown ProcessDialogKey]: Got Menu Key, finding toplevel toolstrip, calling RestoreFocus.");
                      toplevel.RestoreFocusInternal();
                      ToolStripManager.ModalMenuFilter.MenuKeyToggle = true;
                    }
                    ToolStripManager.ModalMenuFilter.ExitMenuMode();
                    return true;
                }
                else if ((keyData & Keys.KeyCode) == Keys.Escape) {
                  SetCloseReason(ToolStripDropDownCloseReason.Keyboard);
                  SelectPreviousToolStrip();
                  return true;  
              
                }
            }
            return base.ProcessDialogKey(keyData);
        }

        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected override bool ProcessDialogChar(char charCode)
        {
            Debug.WriteLineIf(ControlKeyboardRouting.TraceVerbose, "ToolStripDropDown.ProcessDialogChar [" + charCode.ToString() + "]");

            // Since we're toplevel and arent a container control, we've got to do our own mnemonic handling.
            if ((OwnerItem == null || OwnerItem.Pressed) && charCode != ' ')
            {
                if (ProcessMnemonic(charCode))
                {
                    return true;
                }
            }

            return base.ProcessDialogChar(charCode);
        }

        protected internal override bool ProcessMnemonic(char charCode)
        {
            if (!CanProcessMnemonic())
            {
                return false;
            }

            return base.ProcessMnemonic(charCode);
        }

        internal override void ProcessDuplicateMnemonic(ToolStripItem item, char charCode)
        {
            if (!CanProcessMnemonic())
            {
                return;
            }

            if (item != null)
            {
                base.ProcessDuplicateMnemonic(item, charCode);
            }
        }

        internal override void RecreateHandleCore() {
            // If we're visible, then we'll have set our parent hwnd to the active control.
            // That means that re-create handle will set it as our parent, but that's not what
            // we want, since that means that from now on we'll be displayed in that controls
            // client co-ordinates.  To fix this, we first re-parent ourselves back to the 
            // hidden window, do the re-create, then set the parent again.
            if (Visible) {
                ReparentToDropDownOwnerWindow();
            }
            base.RecreateHandleCore();
            if (Visible) {
                ReparentToActiveToolStripWindow();
            }
         }

         private void ResetDropShadowEnabled() {
             DropShadowEnabled = true;
         }

         private void ReparentToActiveToolStripWindow() {
              ToolStripManager.ModalMenuFilter.SetActiveToolStrip(this);
              UnsafeNativeMethods.SetWindowLong(new HandleRef(this, Handle), NativeMethods.GWL_HWNDPARENT, ToolStripManager.ModalMenuFilter.ActiveHwnd);
          }

          private void ReparentToDropDownOwnerWindow() {
              // when we're toplevel we need to parent ourselves to a hidden window
              // this prevents a taskbar entry.
              NativeWindow ownerWindow = DropDownOwnerWindow;
              HandleRef ownerHandle = new HandleRef(ownerWindow, ownerWindow.Handle);
              UnsafeNativeMethods.SetWindowLong(new HandleRef(this, Handle), NativeMethods.GWL_HWNDPARENT, ownerHandle);
          }

          /// <summary>
          ///     VERY similar to Form.ScaleCore
          /// </summary>
          [EditorBrowsable(EditorBrowsableState.Never)]
          protected override void ScaleCore(float dx, float dy) {
              Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, GetType().Name + "::ScaleCore(" + dx + ", " + dy + ")");
              SuspendLayout();
              try {
                  //Get size values in advance to prevent one change from affecting another.
                  Size clientSize = ClientSize;
                  Size minSize = MinimumSize;
                  Size maxSize = MaximumSize;
                  ClientSize = ScaleSize(clientSize, dx, dy);
                  if (!MinimumSize.IsEmpty) {
                      MinimumSize = ScaleSize(minSize, dx, dy);
                  }
                  if (!MaximumSize.IsEmpty) {
                      MaximumSize = ScaleSize(maxSize, dx, dy);
                  }
                 
                  ScaleDockPadding(dx, dy);
    
                  foreach(Control control in Controls) {
                      if (control != null) {
#pragma warning disable 618
                          control.Scale(dx, dy);
#pragma warning restore 618
                      }
                  }                           
              }
              finally {
                  ResumeLayout();
              }
          }

          /// <summary>
          ///     Scale this form.  Form overrides this to enforce a maximum / minimum size.
          /// </summary>
          protected override void ScaleControl(SizeF factor, BoundsSpecified specified) {

              base.ScaleControl(factor, specified);

              Size minSize = MinimumSize;
              Size maxSize = MaximumSize;
              if (!MinimumSize.IsEmpty) {
                  MinimumSize = ScaleSize(minSize, factor.Width, factor.Height);
              }
              if (!MaximumSize.IsEmpty) {
                  MaximumSize = ScaleSize(maxSize, factor.Width, factor.Height);
              }
          }

          /// <summary>
          ///     This is called when the ToolStripDropDownItem sets the DropDown property using CreateDefaultDropDown.
          ///     In this case, the IsAutoGenerated should return true.
          /// </summary>
          internal void SetAutoGeneratedInternal(bool autoGenerated)
          {
                this.isAutoGenerated = autoGenerated;
          }


        /// <summary>
        /// Sync sizes with the ToolStripDropDown
        /// </summary>
        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
            
            Rectangle bounds = new Rectangle(x, y, width, height);
            bounds = GetDropDownBounds(bounds);

            base.SetBoundsCore(bounds.X, bounds.Y, bounds.Width, bounds.Height, specified);
        }


        private void SetTopLevelStyle(bool value) {
            if (IsHandleCreated) {
                // We need to swap they style bits on the window handle
                // we could recreate the handle, but that seems rather expensive.
                int styleFlags = WindowStyle;
                
                if (value) {
                    // setting toplevel = true
                    styleFlags &= ~NativeMethods.WS_CHILD;
                    styleFlags |= NativeMethods.WS_POPUP;
                }
                else {
                    // this is a child window
                    styleFlags &= ~NativeMethods.WS_POPUP;
                    styleFlags |= NativeMethods.WS_CHILD;
                }

                WindowStyle = styleFlags;
                
            }
        }

        protected override void SetVisibleCore(bool visible)
        {
            if (state[stateInSetVisibleCore])
            {
                return;
            }

            state[stateInSetVisibleCore] = true;
            try
            {
                if (visible)
                {
                    if (LayoutRequired)
                    {
                        LayoutTransaction.DoLayout(this, this, PropertyNames.Visible);
                    }
                    
                    // Assume that it's been cancelled so that if we throw we do nothing.
                    bool openingEventCancelled = true;

                    try
                    {
                        // Add opening event.
                        // Snap the foreground window BEFORE calling any user events so they
                        // dont have a chance to activate something else. This covers the case
                        // where someone handles the opening event and throws up a messagebox.
                        IntPtr foregroundWindow = UnsafeNativeMethods.GetForegroundWindow();

                        // Fire Opening event
                        // Cancellable event in which default value of e.Cancel depends on
                        // the number of displayed items >0.
                        CancelEventArgs openEventArgs = new CancelEventArgs(cancel: DisplayedItems.Count == 0);
                        OnOpening(openEventArgs);

                        openingEventCancelled = openEventArgs.Cancel;

                        if (!openingEventCancelled)
                        {
                            // do the actual work to open the window.                            
                            if (TopLevel)
                            {
                                ReparentToActiveToolStripWindow();
                            }

                            if (OwnerToolStrip != null)
                            {
                                OwnerToolStrip.ActiveDropDowns.Add(this);
                                // the act of showing this window can cause a spurious mouse move
                                // in the parent, make sure it retains where the mouse really was.
                                OwnerToolStrip.SnapMouseLocation();

                                // Make sure that mouse capture 
                                // transitions between the owner and dropdown.
                                if (OwnerToolStrip.CaptureInternal)
                                {
                                    CaptureInternal = true;
                                }
                            }
                            base.SetVisibleCore(visible);
                            if (TopLevel)
                            {
                                ApplyTopMost(true);
                            }
                            else if (IsHandleCreated && SafeNativeMethods.IsWindowEnabled(new HandleRef(this, Handle)))
                            {
                                SafeNativeMethods.SetWindowPos(new HandleRef(this, Handle), NativeMethods.HWND_TOP, 0, 0, 0, 0,
                                                             NativeMethods.SWP_NOMOVE | NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOACTIVATE);
                            }
                        }
                    }
                    finally
                    {
                        // Fire the opened event only if we actually opened the control.
                        if (!openingEventCancelled)
                        {
                            OnOpened(EventArgs.Empty);
                        }
                    }
                }
                else
                {
                    if (GetVisibleCore())
                    {
                        ToolStripDropDownCloseReason reason = closeReason;
                        ResetCloseReason();

                        var e = new ToolStripDropDownClosingEventArgs(reason);

                        // Fire Closing Event
                        // Cancel is prepopulated based on AutoClose feature.
                        if (e.CloseReason != ToolStripDropDownCloseReason.CloseCalled)
                        {
                            e.Cancel = !AutoClose;
                        }
                        else
                        {
                            e.Cancel = false;
                        }

                        try
                        {
                            OnClosing(e);
                        }
                        finally
                        {
                            // delay evaluate only in the case we need it
                            if (!e.Cancel)
                            {
                                // setting to not visible.  Dismiss our child drop downs, reset, set ourselves visible false.
                                DismissActiveDropDowns();

                                // Make sure we cancel auto expansion on the root
                                ToolStrip topLevelToolStrip = GetToplevelOwnerToolStrip();
                                ToolStrip parentToolStrip = OwnerItem?.ParentInternal;

                                // We don't consider reason == ToolStripDropDownCloseReason.Keyboard here.
                                // DropDown needs to be closed when Alt or ESC is pressed,
                                // but these two keys are handled in ToolStrip.RestoreFocusInternal()
                                // and ToolStripDropDown.SelectPreviousToolStrip() respectively, 
                                // and ToolStrip.MenuAutoExpand of top level tool strip will be set false there.
                                // Left and Right keys may also close dropdown, but we don't need to
                                // set ToolStrip.MenuAutoExpand of top level tool strip to be false in such cases. 
                                if ((reason == ToolStripDropDownCloseReason.AppClicked) ||
                                    (reason == ToolStripDropDownCloseReason.ItemClicked) ||
                                    (reason == ToolStripDropDownCloseReason.CloseCalled && topLevelToolStrip == parentToolStrip) ||
                                    (reason == ToolStripDropDownCloseReason.AppFocusChange && topLevelToolStrip == parentToolStrip))
                                {
                                    CancelAutoExpand();
                                }

                                // if this came through via a click event we should actually
                                // dismiss everyone in the chain. Other windows will recieve a 
                                // close, closing event with reason AppFocusChange. This is by 
                                // design since the item wasnt clicked on that window.
                                if (reason == ToolStripDropDownCloseReason.ItemClicked)
                                {
                                    // Preserve the SourceControl value up the chain.
                                    saveSourceControl = true;
                                    DismissAll();
            
                                    // make sure that when we roll up, our owner item's selection is cleared.
                                    ToolStripItem rootOwnerItem = GetToplevelOwnerItem();
                                    rootOwnerItem?.Unselect();

                                    ToolStripManager.ModalMenuFilter.RemoveActiveToolStrip(this);

                                    Debug.WriteLineIf(ToolStrip.SnapFocusDebug.TraceVerbose, "[ToolStripDropDown.SetVisibleCore] Exiting menu mode because item clicked");

                                    ToolStripManager.ModalMenuFilter.ExitMenuMode();
                                }
                                else
                                {
                                    ToolStripManager.ModalMenuFilter.RemoveActiveToolStrip(this);
                                }

                                // snap our bounds, we'll need it for some invalidation later.
                                Rectangle bounds = this.Bounds;

                                try
                                {
                                    base.SetVisibleCore(visible);
                                }
                                finally
                                {
                                    // rRmove ourselves from the active dropdown list.
                                    OwnerToolStrip?.ActiveDropDowns.Remove(this);
                                    ActiveDropDowns.Clear();

                                    // If the user traps the click event and starts
                                    // pumping their own messages by calling Application.DoEvents, we 
                                    // should release mouse capture.
                                    if (CaptureInternal)
                                    {
                                        CaptureInternal = false;
                                    }
                                }

                                // Fire OnClosed.
                                // if you make VisibleChanged throw you dont get closed. Sorry.
                                var closedEventArgs = new ToolStripDropDownClosedEventArgs(reason);
                                OnClosed(closedEventArgs);

                                if (TopLevel && (!IsDisposed || !Disposing))
                                {
                                    // Parent back up to our DropDownOwnerWindow.
                                    ReparentToDropDownOwnerWindow();
                                }

                                if (!saveSourceControl)
                                {
                                    Debug.Assert(reason != ToolStripDropDownCloseReason.ItemClicked,
                                        "Why are we resetting SourceControl on a click event?");

                                    // If we're not about to fire a Click event, reset SourceControl.
                                    SourceControlInternal = null;
                                }

                                // Making ourselves look presentable:
                                // We may be about to invoke a click event here... 
                                // if we're the topmost dropdown then invalidate our 
                                // intersection with the toplevel toolstrip
                                if (!DesignMode && IsFirstDropDown && OwnerItem != null && TopLevel)
                                {
                                    ToolStrip toolStrip = GetToplevelOwnerToolStrip();
                                    if (toolStrip != null && !(toolStrip.IsDisposed || toolStrip.Disposing))
                                    {
                                        // translate the bounds (already in screen coords) to toolstrip. 
                                        bounds.Location = toolStrip.PointToClient(bounds.Location);

                                        // find the intersection with the client and use that to invalidate
                                        bounds.Intersect(toolStrip.ClientRectangle);

                                        if (bounds.Width > 0 && bounds.Height > 0)
                                        {
                                            toolStrip.Invalidate(bounds);
                                            toolStrip.Update();
                                        }
                                    }
                                }

                            }
                        }
                    }
                    else
                    {
                        ToolStripManager.ModalMenuFilter.RemoveActiveToolStrip(this);
                    }
                }
            }
            finally
            {
                state[stateInSetVisibleCore] = false;
                saveSourceControl = false;
            }
        }

        private bool ShouldSerializeDefaultDropDownDirection() {
            return (childDropDownDirection != ToolStripDropDownDirection.Default);
        }

        /// <summary>
        ///     Updates the layered window attributes if the control
        ///     is in layered mode.
        /// </summary>
        private void UpdateLayered() {
            if (state[stateLayered] && IsHandleCreated && TopLevel && OSFeature.Feature.IsPresent(OSFeature.LayeredWindows)) {
                bool result;
       
                result = UnsafeNativeMethods.SetLayeredWindowAttributes(new HandleRef(this, Handle), 0, OpacityAsByte, NativeMethods.LWA_ALPHA);
       
                if (!result) {
                    throw new Win32Exception();
                }
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new void Show() {
            // don't set displayLocation here, since all the other Show methods call this.
            base.Show();
        }

        /// <summary> show relative to control coordinates </summary>
        public void Show(Control control, Point position) {
            if (control == null) {
                throw new ArgumentNullException(nameof(control));
            }
            SourceControlInternal = control;
            // When we have no owner item and we're set to RTL.Inherit, translate the coordinates
            // so that the menu looks like it's swooping from the other side
            if (this.OwnerItem == null && control.RightToLeft == RightToLeft.Yes) {
                AdjustSize();
                position.Offset(control.IsMirrored ? Width : -Width, 0);
            }

            this.displayLocation = control.PointToScreen(position);
            this.Location = this.displayLocation;
            ShowCore();
            
        }

        public void Show(Control control, Point position, ToolStripDropDownDirection direction) {
            if (control == null) {
                throw new ArgumentNullException(nameof(control));
            }
            SourceControlInternal = control;
            this.displayLocation = CalculateDropDownLocation(control.PointToScreen(position),  direction).Location;
            this.Location = this.displayLocation;
            ShowCore();
        }

        /// <summary> show relative to control coordinates </summary>
        public void Show(Control control, int x, int y) {
            if (control == null) {
                throw new ArgumentNullException(nameof(control));
            }
            SourceControlInternal = control;
            Show(control, new Point(x,y));
        }


        /// <summary> show relative to screen coordinates </summary>
        public void Show(Point screenLocation) {
            this.displayLocation = screenLocation;
            this.Location = this.displayLocation;
            ShowCore();
        }
        public void Show(Point position, ToolStripDropDownDirection direction) {
            this.displayLocation = CalculateDropDownLocation(position, direction).Location;
            this.Location = this.displayLocation;
            ShowCore();
        }
  

        /// <summary> show relative to screen coordinates </summary>
        public void Show(int x, int y) {
            this.displayLocation = new Point(x,y);
            this.Location = this.displayLocation;
            ShowCore();
        }

        private void ShowCore() {
            Show();
        }
        
        private bool ShouldSerializeDropShadowEnabled() {
             return dropShadowEnabled == false;
        }
        internal override bool ShouldSerializeLayoutStyle() {
            return LayoutStyle != ToolStripLayoutStyle.VerticalStackWithOverflow;
        }
        internal void UnassignDropDownItem() {
            Debug.Assert(countDropDownItemsAssignedTo > 0, "dropdown assignment underflow");
            countDropDownItemsAssignedTo = Math.Max(--countDropDownItemsAssignedTo, 0);
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case Interop.WindowMessages.WM_NCACTIVATE:
                    // if someone clicks on a child control of the toolstrip dropdown, we want 
                    // the title bar to continue appearing active.  Normally we just show without
                    // taking window activation (ShowWindow(SHOWNOACTIVATE)) but we cant stop
                    // child controls from taking focus.
                    WmNCActivate(ref m);
                    return;
                case Interop.WindowMessages.WM_ACTIVATE:
                    // This is the Chrome Panel collection editor scenario
                    // we had focus, then the Chrome panel was activated and we never went away 
                    // when we get focus again, we should reactivate our message filter.
                    Debug.WriteLineIf(ToolStrip.SnapFocusDebug.TraceVerbose, "[ToolStripDropDown.WndProc] got a WM_ACTIVATE " + (((int)m.WParam == NativeMethods.WA_ACTIVE) ? "WA_ACTIVE" : "WA_INACTIVE") + " - checkin if we need to set the active toolstrip");

                    if ((int)m.WParam == NativeMethods.WA_ACTIVE)
                    {
                        if (Visible)
                        {
                            if (ToolStripManager.ModalMenuFilter.GetActiveToolStrip() != this)
                            {
                                // if we were inactive and now we are, we should enter menu mode 
                                ToolStripManager.ModalMenuFilter.SetActiveToolStrip(this);
                            }
                        }
                        else
                        {
                            Debug.Fail("Why are we being activated when we're not visible? Deactivating thingee is " + WindowsFormsUtils.GetControlInformation(m.LParam));
                        }
                    }
                    else
                    {
                        Debug.WriteLineIf(ToolStrip.SnapFocusDebug.TraceVerbose, "[ToolStripDropDown.WndProc] activating thingee is " + WindowsFormsUtils.GetControlInformation(m.LParam));
                    }

                    base.WndProc(ref m);
                    return;
                default:
                    base.WndProc(ref m);
                    return;
            }
        }


#region DropDownSpecific
       internal void DismissAll() {
           ToolStripDropDown toplevel = this.GetFirstDropDown();
           toplevel.closeReason = this.closeReason;
           toplevel.DismissActiveDropDowns();
            if (!LocalAppContextSwitches.UseLegacyContextMenuStripSourceControlValue) {
                toplevel.saveSourceControl = this.saveSourceControl;
            }
            toplevel.Visible = false;
       }
       private void DismissActiveDropDowns() {
           Debug.WriteLineIf((DropDownActivateDebug.TraceVerbose && ActiveDropDowns.Count > 0), "Dismiss children called - COUNT " + ActiveDropDowns.Count + " \r\n" + new StackTrace().ToString());
           int count = ActiveDropDowns.Count;
           if (count == 1) {
               // this is the most common case
               ToolStripDropDown dropDown = ActiveDropDowns[0] as ToolStripDropDown;
               if (dropDown != null) {
                 dropDown.Visible = false;     
               }
       
           }
           else {
               ArrayList dropDowns = ActiveDropDowns.Clone() as ArrayList;
               // We cant iterate through the active dropdown collection
               // here as changing visibility changes the collection.
               for (int i = 0; i < dropDowns.Count; i++) {
                  ToolStripDropDown dropDown = dropDowns[i] as ToolStripDropDown;
                  if (dropDown != null) {
                     dropDown.Visible = false;     
                  }
               }
           }
       }

#region WMNCACTIVATE
       private bool sendingActivateMessage = false;
       
       // WmNcActivate
       // if someone clicks on a child control of the toolstrip dropdown, we want 
       // the title bar to continue appearing active.  Normally we just show without
       // taking window activation (ShowWindow(SHOWNOACTIVATE)) but we cant stop
       // child controls from taking focus.
       private void WmNCActivate(ref Message m) {

            if (m.WParam != IntPtr.Zero /*activating*/) {

                if (!sendingActivateMessage) {
                    sendingActivateMessage = true;
                    try {
                        Debug.WriteLineIf(DropDownActivateDebug.TraceVerbose, "Sending WM_NCACTIVATE to toplevel hwnd" + ToolStripManager.ModalMenuFilter.ActiveHwnd);
                        // we're activating - notify the previous guy that we're activating.
                        HandleRef activeHwndHandleRef = ToolStripManager.ModalMenuFilter.ActiveHwnd;

                        UnsafeNativeMethods.SendMessage(activeHwndHandleRef, Interop.WindowMessages.WM_NCACTIVATE, (IntPtr)1, NativeMethods.InvalidIntPtr);
                        SafeNativeMethods.RedrawWindow(activeHwndHandleRef, null, NativeMethods.NullHandleRef, NativeMethods.RDW_FRAME | NativeMethods.RDW_INVALIDATE);
                        m.WParam = (IntPtr)1;
                    }
                    finally {
                        sendingActivateMessage = false;
                    }
                }
                DefWndProc(ref m);
                return;

            }
            else {
                base.WndProc(ref m);
            }

        }
#endregion
        /// <summary>
        /// Determines if this is the first dropDown in the dropDown chain
        /// </summary>
        internal bool IsFirstDropDown {
            get {
                return ((OwnerToolStrip as ToolStripDropDown) == null);
            }
        }

        /// <summary>
        /// returns the root dropdown in the chain.
        /// </summary>           
        internal ToolStripDropDown GetFirstDropDown() {

            ToolStripDropDown topmost = this;
            // walk back up the chain of windows to get the topmost
            ToolStripDropDown ownerDropDown = topmost.OwnerToolStrip as ToolStripDropDown;
            while (ownerDropDown != null) {
                topmost = ownerDropDown;
                ownerDropDown = topmost.OwnerToolStrip as ToolStripDropDown;
            }
            return topmost;
        }

        internal static ToolStripDropDown GetFirstDropDown(ToolStrip start) {
            Debug.Assert(start != null, "Who is passing null to GetFirstDropDown?");
            if ((start == null) || (!start.IsDropDown)) {
                return null;
            }
            ToolStripDropDown startDropDown = (start as ToolStripDropDown);
            return startDropDown.GetFirstDropDown();
        }


#endregion DropDownSpecific

        [System.Runtime.InteropServices.ComVisible(true)]        
        public class ToolStripDropDownAccessibleObject : ToolStripAccessibleObject {
                private ToolStripDropDown owner;
        
                 public ToolStripDropDownAccessibleObject(ToolStripDropDown owner) : base(owner) {
                     this.owner = owner;
                 }

                  public override string Name {
                    get {
                        // Special case: If an explicit name has been set in the AccessibleName property, use that.
                        // Note: Any non-null value in AccessibleName overrides the default accessible name logic,
                        // even an empty string (this is the only way to *force* the accessible name to be blank).
                        string name = owner.AccessibleName;
                        if (name != null) {
                            return name;
                        }

                        // NOT localized for testing purposes.  Localizers can use AccessibleName.
                        name = "DropDown";
                        
                        if (owner.OwnerItem != null && owner.OwnerItem.AccessibilityObject.Name != null) {
                            name = owner.OwnerItem.AccessibilityObject.Name + name;    
                        }
                       
                        return name;
                    }

                    set {
                        // If anyone tries to set the accessible name, just cache the value in the control's
                        // AccessibleName property. This value will then end up overriding the normal accessible
                        // name logic, until such time as AccessibleName is set back to null.
                        owner.AccessibleName = value;
                    }
                }
                public override AccessibleRole Role {
                    get {
                        AccessibleRole role = Owner.AccessibleRole;
                        if (role != AccessibleRole.Default) {
                            return role;
                        }
                        return AccessibleRole.MenuPopup;
                    }
                }

        }
    }
}

